﻿using System;

namespace Love.Awesome.FluxNET
{
    public class Tween
    {

        /// <summary>
        /// 缓动函数。
        /// </summary>
        public EasingFunctionType EasingFunctionType { get; set; }

        /// <summary>
        /// 缓动的方式。
        /// </summary>
        public EasingInOutMode InOutMode { get; set; }

        /// <summary>
        /// 起点值。
        /// </summary>
        public float From
        {
            get => _from;
            set
            {
                _from = value;
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }
        private float _from;

        /// <summary>
        /// 终点值。
        /// </summary>
        public float To
        {
            get => _to;
            set
            {
                _to = value;
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }
        private float _to;

        /// <summary>
        /// 延迟。
        /// </summary>
        public float Delay
        {
            get => _delay;
            set
            {
                _delay = value;
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }
        private float _delay;

        /// <summary>
        /// 时长。
        /// </summary>
        public float Duration
        {
            get => _duration;
            set
            {
                if (_duration < 0) throw new Exception("时间无法为负数");
                _duration = value;
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }
        private float _duration;


        /// <summary>
        /// 当前的具体进度。
        /// </summary>
        public float Progress
        {
            get => _progress;
            set
            {
                _progress = value;
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }
        private float _progress;


        /// <summary>
        /// 当前的值。
        /// </summary>
        public float CurrentValue => From + (To - From) * EasingFunctionMapper.CalculateEasingFunction(EasingFunctionType, InOutMode, GetAvaliableRate());

        /// <summary>
        /// 动画的播放进度。
        /// </summary>
        public float Rate
        {
            get => GetRate();
            set
            {
                _progress = value * (Delay + Duration);
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }

        /// <summary>
        /// 控制动画数据的更新状态，当<see cref="IsRunning"/>为<see cref="false"/>时，该过渡动画将不再更新，即进入了暂停。
        /// </summary>
        public bool IsRunning { get; private set; }

        /// <summary>
        /// 动画是否循环。
        /// </summary>
        public bool IsLoop { get; set; }

        /// <summary>
        /// 如果没有运行时，是否也能触发事件？
        /// </summary>
        public bool CanRaiseEventInPauseState
        {
            get => _canRaiseEventInPauseState;
            set
            {
                _canRaiseEventInPauseState = value;
                OnValueUpdated?.Invoke(this, CurrentValue);
            }
        }
        private bool _canRaiseEventInPauseState;

        /// <summary>
        /// 在动画在每帧发生更新时。可以结合<see cref="CanRaiseEventInPauseState"/>使用。
        /// </summary>
        public event EventHandler<float> OnValueUpdated;

        /// <summary>
        /// 在动画完成被销毁时。
        /// </summary>
        public event EventHandler OnCompleted;


        internal Tween(float duration, float delay, float from, float to)
        {
            _delay = delay;
            _duration = duration;
            _progress = 0;
            _from = from;
            _to = to;

            EasingFunctionType = EasingFunctionType.Quad;
            InOutMode = EasingInOutMode.Out;
            IsRunning = true;
            IsLoop = false;
            _canRaiseEventInPauseState = false;



            OnValueUpdated = null;
            OnCompleted = null;

        }



        private Tween(Tween tween)
        {
            _delay = tween._delay;
            _duration = tween._duration;
            _progress = tween._progress;
            _from = tween._from;
            _to = tween._to;

            EasingFunctionType = tween.EasingFunctionType;
            InOutMode = tween.InOutMode;
            IsRunning = tween.IsRunning;
            IsLoop = tween.IsLoop;
            _canRaiseEventInPauseState = tween._canRaiseEventInPauseState;

            OnValueUpdated = null;
            OnCompleted = null;
        }

        public Tween Clone(Tween tween)
        {
            return new Tween(tween);
        }

        public void Update(float dt)
        {
            if (IsRunning)
            {
                _progress += dt;
                if (IsLoop == true && _progress > _delay + _duration)
                {
                    _progress -= _delay + _duration;
                }
            }


            if (IsRunning == true || CanRaiseEventInPauseState == true)
            {
                OnValueUpdated?.Invoke(this, CurrentValue);
            }

        }

        /// <summary>
        /// 激活动画，使其能够参与表达式的更新。
        /// </summary>
        public void Run()
        {
            if (IsRunning == false)
            {
                IsRunning = true;
            }


            OnValueUpdated?.Invoke(this, CurrentValue);

        }

        /// <summary>
        /// 暂停计时状态。
        /// </summary>
        public void Stop()
        {
            if (IsRunning == true)
            {
                IsRunning = false;
            }

            OnValueUpdated?.Invoke(this, CurrentValue);

        }


        internal void RaiseCompletedEvent()
        {
            OnCompleted?.Invoke(this, EventArgs.Empty);
        }

        private float GetRate(float progress)
        {
            //var trueProgress = progress - Delay;
            //var result = trueProgress / Duration;
            //if (result < 0) return 0;
            //if (result > 1) return 1;
            return progress / (Delay + Duration);
        }

        private float GetAvaliableRate(float progress)
        {
            var trueProgress = progress - Delay;
            var result = trueProgress / Duration;
            if (result < 0) return 0;
            if (result > 1) return 1;
            return result;
        }

        private float GetAvaliableRate()
        {
            return GetAvaliableRate(_progress);
        }

        private float GetRate()
        {
            return GetRate(_progress);
        }


        public void DrawDebug()
        {
            int count = 50;
            float[] result = new float[count + 1];
            float internalLength = Graphics.GetWidth() / (float)count;
            float internalHeight = Mathf.Min(Graphics.GetWidth(), Graphics.GetHeight())/5;

            var height = Graphics.GetHeight();

            for (int i = 0; i <= count; i++)
            {
                var rate = i / (float)count;
                result[i] = EasingFunctionMapper.CalculateEasingFunction(EasingFunctionType, InOutMode, rate);
            }

            for (int i = 0; i <= count; i++)
            {
                Graphics.Circle(DrawMode.Fill, i * internalLength, height - result[i] * internalHeight, 2);
                if (i != count)
                    Graphics.Line(
                        new Vector2() { X = i * internalLength, Y = height - result[i] * internalHeight },
                        new Vector2() { X = (1 + i) * internalLength, Y = height - result[i + 1] * internalHeight });
            }

        }

    }
}
